/************************************************/
/**				blk.h by doom119				*/
/**					June, 2010					*/
/************************************************/
#ifndef _BLK_H_
#define _BLK_H_
#include <task.h>
#include <fs.h>

#define NR_BLK_DEV	7 // the amounts of block devices
#define NR_REQUEST 32 // the amounts of request items,
					  // and writes use the low 2/3 of these
					  // of course, reads use the high 1/3 of these

#define MAJOR(device) (((unsigned)(device)) >> 8)
#define MINOR(device) ((device)&0xff)

#define WRITE 0
#define READ 1

struct request
{
	unsigned short dev;
	int cmd;
	int errors;
	unsigned long start_sector; //start sector, one block equals to  two sectors
	unsigned long nr_sectors; //the amounts of sectors that should be operated
	char * buffer;
	struct task *wait;
	struct buffer_head *bh;
	struct request *next;
};

struct block_device
{
	void (*request_fn)(void);
	struct request *current_request;
};

extern struct block_device blk_dev[NR_BLK_DEV];
extern struct request request[NR_REQUEST];
extern struct task *wait_for_request;

#ifdef MAJOR_NR

#if (MAJOR_NR == 3) // hard disk
#define DEVICE_NAME "HARD DISK"
#define DEVICE_INTERRUPT do_hd
#define DEVICE_REQUEST do_hd_request
#define DEVICE_NR(device) (MINOR(device)/5)
#define DEVICE_ON
#define DEVICE_OFF
#else
#error "unknown block devices"
#endif


#ifdef DEVICE_INTERRUPT
void (*DEVICE_INTERRUPT)(void) = 0;
#endif

static void (DEVICE_REQUEST)(void);

#define CURRENT_REQUEST (blk_dev[MAJOR_NR].current_request)
#define CURRENT_DEV DEVICE_NR(CURRENT_REQUEST->dev)

extern inline void unlock_buffer(struct buffer_head *bh)
{
	if(!bh->lock)
		printk("hd unlock_buffe");
	bh->lock = 0;
	wake_up(&bh->wait);
}

extern inline void end_request(int uptodate)
{
	DEVICE_OFF(CURRENT_REQUEST->dev);
	if(CURRENT_REQUEST->bh)
	{
		CURRENT_REQUEST->bh->uptodate = uptodate;
		unlock_buffer(CURRENT_REQUEST->bh);
	}
	if(!uptodate)
	{
		printk("hd end_request ");
	}

	wake_up(&CURRENT_REQUEST->wait);
	wake_up(&wait_for_request);
	CURRENT_REQUEST->dev = -1;
	CURRENT_REQUEST = CURRENT_REQUEST->next;
}

#endif
#endif
